<?php

/**
 * @classname 用户
 * @classaccess public
 * @decription 用户接口
 * @author 张旭刚
 * @updateTime 2020年06月21日
 */

namespace api\controllers;

use Yii;
use api\models\Smscode;
use api\models\Members;
use api\models\Membertokens;
use api\models\Memberinfos;

class MembersController extends PublicController {

    private $reg_login_key;//登录手机号暂存器

    public function __construct($id, $module, $config = array()) {
        parent::__construct($id, $module, $config);
        $this->reg_login_key = 'reg_login_mobiles';
    }

    /**
     * @see 发送验证码短信
     * @describe 发送验证码短信接口
     * @access public
     * @name send-verify-sms
     * @method POST
     * @requestType FORM
     * @defget no
     * @author 张旭刚,2020年6月21日,创建
     * 
     * @param mobile|string|required|手机号
     * @param captcha|string|required|图片验证码
     * 
     * @header guid|string|required|客户端唯一编号
     * 
     * @return result|string|成功/失败（true/false）
     */
    public function actionSendVerifySms() {
        $guid = $this->headers['guid'];
        if(empty($guid)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => 'GUID不能为空', 'errorCode' => 103001]);
        }
        $mobile = Yii::$app->request->post('mobile');
        if(empty($mobile)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '手机号不能为空', 'errorCode' => 103003]);
        }
        $captcha = Yii::$app->request->post('captcha');
        if(empty($captcha)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '图片验证码不能为空', 'errorCode' => 103002]);
        }
        $cacheKey = 'captchas';
        $code = $this->redis->hget($cacheKey, $guid);
        if(empty($code)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '图片验证码错误', 'errorCode' => 103004]);
        }
        if($code != $captcha){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '图片验证码错误', 'errorCode' => 103005]);
        }
        $serviceType = 'login';
        $cm = Smscode::find()->where(['mobile' => $mobile, 'serviceType' => $serviceType])->one();
        $baseStr = $mobile . '_' . microtime() . '_' . $serviceType;
        $salt = $this->setting('code_key_salt');
        if(empty($cm)){
            $m = new Smscode();
            $m->codeKey = $this->sha256($baseStr, $salt);
        } else {
            $m = Smscode::findOne($cm->codeId);
            $limitLong = intval($this->setting('code_sms_resend_limit_long'));
            if(time() - $cm->stime <= $limitLong){
                return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '短信不能连续发送，请间隔一定时间后再发送', 'errorCode' => 103006]);
            }
        }
        $codes = $this->createCode(6, 'number');
        $code = implode('', $codes);
        $content = str_replace('{code}', $code, $this->setting('code_sms_template'));
        $status = $this->sendSms($mobile, $content);
        $m->code = $code;
        $m->mobile = $mobile;
        $m->status = $status;
        $m->serviceType = $serviceType;
        $m->stime = time();
        $m->save();
        $this->redis->hset($this->reg_login_key, $guid, $mobile);
        return $this->renderJson(['code' => 1, 'result' => true, 'msg' => '发送验证码成功', 'errorCode' => 0]);
    }

    /**
     * @see 登录
     * @describe 执行登录和注册（首次登录执行的是注册过程）
     * @access public
     * @name login
     * @method POST
     * @requestType FORM
     * @defget no
     * @author 张旭刚,2020年6月22日,创建
     * 
     * @header guid|string|required|客户端唯一编号
     * 
     * @param verify|string|required|短信验证码
     * 
     * @return result|string|登录结果
     */
    public function actionLogin(){
        $guid = $this->headers['guid'];
        if(empty($guid)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => 'GUID不能为空', 'errorCode' => 103007]);
        }
        $mobile = $this->redis->hget($this->reg_login_key, $guid);
        if(empty($mobile)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '登录操作非法', 'errorCode' => 103008]);
        }
        $verify = Yii::$app->request->post('verify');
        $smscode = Smscode::findOne(['mobile' => $mobile]);
        $effectime = $this->setting('sms_code_effective_time');
        if(time() - $smscode->stime > $effectime){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '短信验证码已经过期', 'errorCode' => 103010]);
        }
        if($smscode->code != $verify){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '短信验证码错误', 'errorCode' => 103009]);
        }
        $m = Members::findOne(['mobile' => $mobile]);
        if(empty($m)){//执行注册过程
            $m = new Members();
            $m->mobile = $mobile;
            $baseStr = $mobile.'_'.$verify.'_'.microtime();
            $salt = $this->setting('user_key_salt');
            $m->memberKey = $this->sha256($baseStr, $salt);
            $m->save();
        }
        //执行登录过程：产生Token,和refreshtoken
        $salt = $this->setting('user_login_salt');
        $tokenBase = $guid . '_' . $mobile .'_'.$verify.'_'.microtime();
        $refreshTokenBase = $verify . '_' . $mobile .'_'.$guid.'_'.microtime().'_'.rand(100000, 999999);
        $token = $this->sha256($tokenBase, $salt);
        $refreshToken = $this->sha256($refreshTokenBase, $salt);
        $t = Membertokens::findOne(['memberKey' => $m->memberKey]);
        if(empty($t)){//如果不存在则新建
            $t = new Membertokens();
        }
        $t->memberId = $m->memberId;
        $t->mobile = $m->mobile;
        $t->memberKey = $m->memberKey;
        $t->token = $token;
        $t->refreshToken = $refreshToken;
        $t->ctime = time();
        $t->save(false);
        $this->redis->hdel($this->reg_login_key, $guid);
        $data = ['token' => $token, 'refreshToken' => $refreshToken, 'effective' => $this->setting('user_login_token_limit_long')];
        return $this->renderJson(['code' => 1, 'result' => $data, 'msg' => '登录成功', 'errorCode' => 0]);
    }

    /**
     * @see 登记检查
     * @describe 检查是否做过登记接口
     * @access public
     * @name check-in
     * @method POST
     * @requestType FORM
     * @defget no
     * @author 张旭刚,2020年6月22日,创建
     * 
     * @header guid|string|required|客户端唯一编号
     * @header token|string|required|用户登录证书
     * 
     * @return result|string|登录结果
     */
    public function actionCheckIn(){
        $m = Memberinfos::findOne(['memberKey' => $this->memberKey]);
        if(empty($m)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '未做身份登记', 'errorCode' => 103011]);
        }
        if(empty($m->idCardNo) || empty($m->realName)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '身份信息登记不完善', 'errorCode' => 103012]);
        }
        return $this->renderJson(['code' => 1, 'result' => false, 'msg' => '身份已经登记', 'errorCode' => 0]);
    }

    /**
     * @see 身份登记
     * @describe 身份登记接口
     * @access public
     * @name register
     * @method POST
     * @requestType FORM
     * @defget no
     * @author 张旭刚,2020年6月22日,创建
     * 
     * @header guid|string|required|客户端唯一编号
     * @header token|string|required|用户登录证书
     * 
     * @param realName|string|required|用户登录证书
     * @param idCardNo|string|required|用户登录证书
     * 
     * @return result|string|登录结果
     */
    public function actionRegister(){
        $realName = Yii::$app->request->post('realName');
        if(empty($realName)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '姓名不能为空', 'errorCode' => 103013]);
        }
        $idCardNo = Yii::$app->request->post('idCardNo');
        if(empty($idCardNo)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '身份证号不能为空', 'errorCode' => 103014]);
        }
        if(strlen($idCardNo) != 15 && strlen($idCardNo) != 18){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '身份证号格式不正确', 'errorCode' => 103015]);
        }
        $m = Memberinfos::findOne(['memberKey' => $this->memberKey]);
        if(empty($m)){
            $m = new Memberinfos();
        }
        //这里可以加入对身份证认证接口，如果需要的话
        $m->memberKey = $this->memberKey;
        $m->realName = $realName;
        $m->idCardNo = $idCardNo;
        $m->ctime = time();
        if(!$m->save(false)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '身份登记失败，请稍后再试', 'errorCode' => 103016]);
        }
        return $this->renderJson(['code' => 1, 'result' => false, 'msg' => '身份登记成功', 'errorCode' => 0]);
    }

    /**
     * @see Token刷新
     * @describe 登录令牌刷新
     * @access public
     * @name refresh-token
     * @method POST
     * @requestType FORM
     * @defget no
     * @author 张旭刚,2020年6月27日,创建
     * 
     * @header guid|string|required|客户端唯一编号
     * 
     * @param refreshToken|string|required|刷新令牌
     * @param token|string|required|用户登录证书
     * 
     * @return token|string|登录令牌
     * @return refreshToken|string|登录令牌刷新凭证
     * @return effective|string|登录令牌有效期
     */
    public function actionRefreshToken(){
        $guid = $this->headers['guid'];
        $refreshToken = Yii::$app->request->post('refreshToken');
        $token = Yii::$app->request->post('token');
        $tokens = Membertokens::findOne(['token' => $token, 'refreshToken' => $refreshToken]);
        $refreshTokenLimitLong = $this->setting('user_login_refresh_token_limit_long');
        if(empty($tokens)){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '刷新凭证无效', 'errorCode' => 103017]);
        }
        if(time() - $tokens->ctime > $refreshTokenLimitLong){
            return $this->renderJson(['code' => 0, 'result' => false, 'msg' => '刷新凭证无效', 'errorCode' => 103018]);
        }
        $tokenBase = $guid . '_' . $tokens['mobile'] .'_'.rand(100000, 999999).'_'.microtime();
        $refreshTokenBase = rand(100000, 999999) . '_' . $tokens['mobile'] .'_'.$guid.'_'.microtime().'_'.rand(100000, 999999);
        $salt = $this->setting('user_login_salt');
        $tokens->token = $this->sha256($tokenBase, $salt);
        $tokens->refreshToken = $this->sha256($refreshTokenBase, $salt);
        $tokens->ctime = time();
        $tokens->save();
        $data = ['token' => $tokens->token, 'refreshToken' => $tokens->refreshToken, 'effective' => $this->setting('user_login_token_limit_long')];
        return $this->renderJson(['code' => 1, 'result' => $data, 'msg' => '刷新成功', 'errorCode' => 0]);
    }
}
